package com.turing.data.service.review.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.netflix.discovery.converters.Auto;
import com.turing.common.exception.ServiceException;
import com.turing.common.response.CommonCode;
import com.turing.common.util.*;
import com.turing.data.dao.review.ModelContentMapper;
import com.turing.data.dao.review.ReviewContentMapper;
import com.turing.data.inner.DrawTaskInnerService;
import com.turing.data.inner.FileTaskInnerService;
import com.turing.data.inner.TaskRecordInnerService;
import com.turing.data.model.domain.element.Element;
import com.turing.data.model.domain.element.Template;
import com.turing.data.model.domain.review.ModelContent;
import com.turing.data.model.domain.review.ReviewContent;
import com.turing.data.model.dto.produre.ExportFileDto;
import com.turing.data.model.dto.produre.TaskRecordDto;
import com.turing.data.model.dto.review.ReviewContentDto;
import com.turing.data.model.vo.produre.TaskRecordVo;
import com.turing.data.service.element.ElementService;
import com.turing.data.service.element.TemplateService;
import com.turing.data.service.excel.ExportFieldService;
import com.turing.data.service.review.ReviewContentService;
import com.turing.data.service.review.ReviewOperationService;
import com.turing.data.vo.in.element.ReviewContentVo;
import com.turing.data.vo.in.review.ForecastVO;
import com.turing.data.vo.out.review.ResultVO;
import com.turing.data.vo.out.review.TaskElementVO;
import com.turing.orm.handler.DateTableNameParser;
import lombok.AllArgsConstructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ReviewOperationServiceImpl implements ReviewOperationService {

    private static final Log logger = LogFactory.getLog(ReviewOperationServiceImpl.class);

    /**
     * draw服务draw接口
     */
    @Autowired
    private  FileTaskInnerService fileTaskInnerService;

    /**
     * draw服务element接口
     */
    @Autowired
    private ElementService elementService;

    /**
     * draw服务draw接口
     */
    @Autowired
    private ReviewContentService reviewContentService;

    @Autowired
    private ModelContentMapper modelContentMapper;

    /**
     * procedure服务feign接口
     */
    @Autowired
    private TaskRecordInnerService taskRecordInnerService;

    /**
     * 场景feign接口
     */
    @Autowired
    private TemplateService templateService;

    /**
     * 导出字段信息service
     */
    @Autowired
    private ExportFieldService exportFieldService;

    @Autowired
    private DrawTaskInnerService drawTaskInnerService;

    @Override
    public boolean finishReviewTask(String taskSn) {
        String getTaskSn = fileTaskInnerService.queryParentTask(taskSn);
        //如果本身就是父任务，返回自身
        String parentTaskSn = "0".equals(getTaskSn) ? taskSn : getTaskSn;
        //AssertUtil.isTrue(reviewOperationService.finishTask(parentTaskSn) == 0,"任务未审核完，无法提交!");

        logger.info(">>>>>>>> origin task sn is " + taskSn);

        logger.info(">>>>>>>> query parent task sn is " + parentTaskSn);

        //关闭要素审核
        Integer version = fileTaskInnerService.queryParentTaskVersion(parentTaskSn);
        taskRecordInnerService.finishReview(version, parentTaskSn);
        //判断场景是否需要自动导出
        String taskTemplate = drawTaskInnerService.getTaskTemplate(taskSn);
        //if ("37".equals(taskTemplate)) {
        //    uploadFiLe(parentTaskSn);
        //}
        return true;
    }

    /**
     * 上传文件
     *
     * @param exportFileDto 服务器信息
     * @author lcy
     * @date 2021/8/17 14:28
     **/
    @Override
    public void uploadFiLe(ExportFileDto exportFileDto) {
        Template template = null;
        if (Tools.isNotEmpty(exportFileDto.getTemplateId())) {
            template = templateService.getTemplateById(exportFileDto.getTemplateId());
        } else if (Tools.isNotEmpty(exportFileDto.getTemplateName())) {
            template = templateService.getTemplateByName(exportFileDto.getTemplateName());
        }
        AssertUtil.isEmpty(template, "场景信息为空");
        //转换数据
        List<Object> objectList = new ArrayList<>();
        //设置导出参数
        ExportParams exportParams = new ExportParams();
        exportParams.setSheetName(template.getTemplateName());
        //设置导出类型
        exportParams.setType(ExcelType.XSSF);
        List<ExcelExportEntity> excelEntityList = exportFieldService.getByTemplateId(template.getTemplateSn()).stream()
                .map(exportField -> new ExcelExportEntity(exportField.getFieldName(), exportField.getFieldName(), 40))
                .collect(Collectors.toList());

        //封装参数
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String fileName = template.getTemplateName() + "_" + date + ".xlsx";
        File exportFile = new File(ExcelUtils.EXPORT_PATH + date);
        if (!exportFile.exists()) {
            exportFile.mkdirs();
        }
        exportFile = new File(ExcelUtils.EXPORT_PATH + date + "/" + fileName);
        try (Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelEntityList, objectList);
             FileOutputStream fileOutputStream = new FileOutputStream(exportFile)) {
            workbook.write(fileOutputStream);
            String path = exportFileDto.getPrefixPath() + exportFileDto.getSuffixPath();
            //将windows文件符转成linux
            path = path.replace("\\\\", "/");
            path = path.replace("\\", "/");
            int index = path.indexOf("/");
            if (index == 0) {
                path = path.substring(1);
            }
            //将路径拆分
            index = path.indexOf("/");
            //共享根路径
            String rootDir;
            //需要查找的子目录
            String searchDir;
            if (index == -1) {
                rootDir = path;
                searchDir = "";
            } else {
                rootDir = path.substring(0, index);
                searchDir = index == path.length() - 1 ? "" : path.substring(index + 1);
            }

            if (searchDir.length() - 1 != searchDir.lastIndexOf("/")) {
                searchDir = searchDir + "/";
            }
            //上传文件
            SmbUtil.writeBySmb(exportFileDto, exportFile, rootDir, searchDir + fileName);
            exportFile.delete();
        } catch (IOException e) {
            logger.error(e);
            throw new ServiceException("上传到服务器失败");
        }

    }

    @Override
    @Transactional
    public boolean addSingle(ReviewContentVo contentVo) {


        // head
        if(contentVo.getFirstSequence()==1){
            DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
            reviewContentService.lambdaUpdate().eq(ReviewContent::getFirstSequence, 1)
                    .eq(ReviewContent::getTaskSn, contentVo.getTaskSn())
                    .eq(ReviewContent::getEleId, contentVo.getEleId())
                    .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                    .set(ReviewContent::getFirstSequence, 0).update();
        }

        ReviewContent content = new ReviewContent(contentVo);


        DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
        reviewContentService.lambdaUpdate().eq(ReviewContent::getNextSequence, content.getNextSequence())
                .eq(ReviewContent::getTaskSn, content.getTaskSn())
                .eq(ReviewContent::getEleId, content.getEleId())
                .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                .set(ReviewContent::getNextSequence, content.getSequence()).update();

        DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
        return reviewContentService.save(content);

    }

    @Override
    @Transactional
    public boolean delSingle(ReviewContentVo contentVo) {

        ReviewContent content = new ReviewContent(contentVo);
        DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
        //reviewContentService.removeById(content.getId());
        LambdaQueryWrapper<ReviewContent> removeWrapper = new LambdaQueryWrapper<>();
        removeWrapper.eq(ReviewContent::getTaskSn, content.getTaskSn())
                .eq(ReviewContent::getEleId, content.getEleId())
                .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                .eq(ReviewContent::getSequence,contentVo.getSequence());
        reviewContentService.remove(removeWrapper);

        LambdaUpdateWrapper<ReviewContent> updateWrapper = new LambdaUpdateWrapper<>();

        if(content.getFirstSequence() == 0){
            // update precursor node
            updateWrapper.eq(ReviewContent::getNextSequence, content.getSequence())
                    .eq(ReviewContent::getTaskSn, content.getTaskSn())
                    .eq(ReviewContent::getEleId, content.getEleId())
                    .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                    .set(ReviewContent::getNextSequence, content.getNextSequence());
        }else{
            // change first node
            updateWrapper.eq(ReviewContent::getSequence, content.getNextSequence())
                    .eq(ReviewContent::getTaskSn, content.getTaskSn())
                    .eq(ReviewContent::getEleId, content.getEleId())
                    .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                    .set(ReviewContent::getFirstSequence, 1);
        }
        DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
        return reviewContentService.update(null,updateWrapper);

    }

    @Override
    @Transactional
    public boolean addBatch(List<ReviewContentVo> contentVos) {
        contentVos.forEach(this::addSingle);
        return true;
    }

    @Override
    @Transactional
    public boolean delBatch(List<ReviewContentVo> contentVos) {
        contentVos.forEach(this::delSingle);
        return true;
    }

    @Override
    @Transactional
    public boolean addRow(List<ReviewContentVo> contentVos) {
        // first row
        if(Tools.isNotEmpty(contentVos) && contentVos.get(0).getFirstRow()==1){
            ReviewContentVo contentVo = contentVos.get(0);
            DateTableNameParser.setTaskSn(Long.parseLong(contentVo.getTaskSn()));
            reviewContentService.lambdaUpdate().eq(ReviewContent::getFirstRow, 1)
                    .eq(ReviewContent::getTaskSn, contentVo.getTaskSn())
                    .eq(ReviewContent::getEleId, contentVo.getEleId())
                    .eq(ReviewContent::getSubProductId,contentVo.getSubProductId())
                    .set(ReviewContent::getFirstRow, 0).update();
        }

        contentVos.forEach(c->{
            LambdaUpdateWrapper<ReviewContent> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ReviewContent::getNextRow, c.getNextRow())
                    .eq(ReviewContent::getTaskSn, c.getTaskSn())
                    .eq(ReviewContent::getEleId, c.getEleId())
                    .eq(ReviewContent::getSubProductId,c.getSubProductId())
                    .set(ReviewContent::getNextRow, c.getRowSequence());
            DateTableNameParser.setTaskSn(Long.parseLong(c.getTaskSn()));
            reviewContentService.update(null,updateWrapper);

            DateTableNameParser.setTaskSn(Long.parseLong(c.getTaskSn()));
            reviewContentService.save(new ReviewContent(c));
        });
        return true;
    }

    @Override
    @Transactional
    public boolean delRow(List<ReviewContentVo> contentVos) {

        contentVos.forEach(c->{
            DateTableNameParser.setTaskSn(Long.parseLong(c.getTaskSn()));
            reviewContentService.removeById(c.getId());
            LambdaUpdateWrapper<ReviewContent> updateWrapper = new LambdaUpdateWrapper<>();
            if(c.getFirstRow()==0){
                // update precursor node
                updateWrapper.eq(ReviewContent::getNextRow, c.getRowSequence())
                        .eq(ReviewContent::getTaskSn, c.getTaskSn())
                        .eq(ReviewContent::getEleId, c.getEleId())
                        .eq(ReviewContent::getSubProductId,c.getSubProductId())
                        .set(ReviewContent::getNextRow, c.getNextRow());
            }else{
                // change first row
                updateWrapper.eq(ReviewContent::getRowSequence, c.getNextRow())
                        .eq(ReviewContent::getTaskSn, c.getTaskSn())
                        .eq(ReviewContent::getEleId, c.getEleId())
                        .eq(ReviewContent::getSubProductId,c.getSubProductId())
                        .set(ReviewContent::getFirstRow, 1);
            }
            DateTableNameParser.setTaskSn(Long.parseLong(c.getTaskSn()));
            reviewContentService.update(null,updateWrapper);
        });
        return true;

    }

    @Override
    public boolean uploadModelContent(List<ModelContent> modelContents) {


        modelContents.forEach(
            c->{
                DateTableNameParser.setTaskSn(Long.parseLong(c.getTaskSn()));
                modelContentMapper.insert(c);
            }

        );
        return true;

    }

    @Override
    public boolean populateEmptyElements(String taskSn, String templateSn) {

        List<Element> elements = elementService.getElementsByTemplateSn(templateSn,0);
        if(Tools.isNotEmpty(elements)){
            DateTableNameParser.setTaskSn(Long.parseLong(taskSn));
            List<ModelContent> resultList =  new LambdaQueryChainWrapper<>(modelContentMapper)
                    .select(ModelContent::getModelEleId)
                    .eq(ModelContent::getTaskSn, taskSn)
                    .list();
            List<Integer> occurredIds = resultList.stream().map(ModelContent::getModelEleId).collect(Collectors.toList());
            List<Element> emptyElements = elements.stream().filter(e -> !occurredIds.contains(e.getId())).collect(Collectors.toList());
            if(Tools.isNotEmpty(emptyElements)){
                List<ModelContent> toInsert = new ArrayList<>();
                emptyElements.forEach(
                        e->{
                            ModelContent modelContent = ModelContent.builder()
                                    .taskSn(taskSn)
                                    .modelEleId(e.getId())
                                    .modelEleName(e.getName())
                                    .text("")
                                    .businessValue("")
                                    .start(0)
                                    .end(1)
                                    .degree("0")
                                    .endLineNo(0)
                                    .paraInfo("[]")
                                    .pos("[]")
                                    .posInfo("[0,1]")
                                    .startLineNo(0)
                                    .childTaskSn("").build();
                            toInsert.add(modelContent);
                        }
                );
                uploadModelContent(toInsert);
                return true;
            }
        }
        return false;

    }

    @Override
    public void completeProductTask(List<String> allTaskSns) {

        QueryWrapper<ReviewContent> queryWrapper = new QueryWrapper<>();
        for (String taskSn : allTaskSns) {
            queryWrapper.clear();
            String taskTemplate = drawTaskInnerService.getTaskTemplate(taskSn);
            List<String> elementIds = elementService.getElementsByTemplateSn(taskTemplate,1).stream().filter(element -> element.getSelected() == 1).map(element -> element.getId().toString()).collect(Collectors.toList());
            //校验是否所有元素已经审核完成
            queryWrapper.eq("task_sn", taskSn).in("ele_id", elementIds).eq("taskStatus", 0).gt("version", -1);
            //根据任务的id查询审核记录
            Integer count = reviewContentService.count(queryWrapper);
            if (count == 0) {
                //调用审核完成
                finishReviewTask(taskSn);
            }
        }

    }

    /**
     * 根据产品合同场景某一个任务id获取其它未完成任务id
     *
     * @param taskSn 任务id
     * @return java.util.List<java.lang.String>
     * @author lcy
     * @date 2021/6/16 17:29
     **/
    private List<String> getAllTaskSn(String taskSn) {
        Set<String> productTemplateIds = templateService.getProductTemplate();
        //获取子场景的要素信息
        TaskRecordDto taskRecordDto = TaskRecordDto.builder().taskSn(taskSn).build();
        //根据任务id获取任务信息
        TaskRecordVo taskRecordVo = taskRecordInnerService.getTaskRecord(taskRecordDto).getData().get(0);
        taskRecordDto.setTaskSn(null);
        taskRecordDto.setTaskName(taskRecordVo.getTaskName());
        taskRecordDto.setTemplateIds(new ArrayList<>(productTemplateIds));
        //根据任务信息和场景id获取所有任务详情
        return taskRecordInnerService.getTaskRecord(taskRecordDto).getData().stream().map(TaskRecordVo::getTaskSn).collect(Collectors.toList());
    }

    public Integer countUnFinish(String parentTaskSn) {

        Integer version = fileTaskInnerService.queryParentTaskVersion(parentTaskSn);

        /*if (!StringUtils.isEmpty(parentTaskSn)) {
            return new LambdaQueryChainWrapper<>(reviewContentMapper)
                    .eq(ReviewContent::getTaskSn, parentTaskSn)
                    .eq(ReviewContent::getStatus, 0)
                    .eq(ReviewContent::getVersion, version)
                    .count();
        }*/
        return -1;
    }

    @Override
    public boolean updateReviewContent(ReviewContentVo reviewContentVo) {
        ReviewContent content = new ReviewContent(reviewContentVo);
        DateTableNameParser.setTaskSn(Long.parseLong(content.getTaskSn()));
        LambdaUpdateWrapper<ReviewContent> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ReviewContent::getSequence,reviewContentVo.getSequence())
                .eq(ReviewContent::getTaskSn,reviewContentVo.getTaskSn())
                .eq(ReviewContent::getEleId,reviewContentVo.getEleId());
        return reviewContentService.update(content,updateWrapper);
    }

    @Override
    public void saveModelContents(Map<String, List<ForecastVO>> forecastEntity, String taskSn, String parentTaskSn, List<Element> elements) {
        if(Tools.isNotEmpty(elements)){
            for (Element element : elements) {
                String name = element.getName();
                List<ForecastVO> forecastVOS = forecastEntity.get(name);
                List<ModelContent> modelContents = new ArrayList<>();
                if (Tools.isNotEmpty(forecastVOS)) {
                    for (ForecastVO forecastVO : forecastVOS) {
                        ModelContent modelContent = new ModelContent(forecastVO);
                        modelContent.setTaskSn(parentTaskSn);
                        modelContent.setChildTaskSn(taskSn);
                        modelContent.setModelEleId(element.getId());
                        logger.info(">>>>> upload content is " + modelContent);
                        modelContents.add(modelContent);
                    }
                }else{
                    ModelContent modelContent = ModelContent.builder()
                            .taskSn(parentTaskSn)
                            .modelEleId(element.getId())
                            .modelEleName(element.getName())
                            .text("")
                            .businessValue("")
                            .start(0)
                            .end(1)
                            .degree("0")
                            .endLineNo(0)
                            .paraInfo("[]")
                            .pos("[]")
                            .posInfo("[0,1]")
                            .startLineNo(0)
                            .childTaskSn("").build();
                    modelContents.add(modelContent);
                }
                uploadModelContent(modelContents);
            }
        }
    }

    @Override
    public Boolean removeTasks(List<String> parentTaskSns) {

        // TODO
        return null;

    }

}
